#!/usr/bin/python

# make-tour.py
# Generate a KML tour given a pile of coordinates.
# 
# Copyright Borkware 2009 . All rights reserved.


# make-tour.py - slurp in a LineString coordinates, and blort out
# something that'll make a google earth tour.

# arguments:
#    -n : name of the place (displayed in the Places panel)
#    -c : line color (of the form RRGGBBAA, hex)
#    -w : line width
#    -t : tilt
#    -h : heading
#    -r : range
#    -s : tour speed (delay)
#    -f : follow path?  (YES | NO)
#    -l : lookit-that (lat,lng)
#    -R : reverse path?  (YES | NO)

import getopt
import math
import sys

# pick up the tweakable settings

# 0.0001 is smooth, but big and slow
playback_smoothness = 0.0002
place_name = "Path from Boogie"

tilt = 38.0
heading = -35.0
range = 2000.0

line_width = 3.0
line_color = 'ff0000ff'

# the delay to use between point updates.
tour_speed = 0.05

reverse_path = False


# Apply command-line arguments.

try:
    opts, args = getopt.getopt(sys.argv[1:], 'n:c:w:t:h:r:j:s:f:l:R:')
except getopt.GetoptError, err:
    print "oops - not enough args in getopt"
    sys.exit(1)

forceLookAt = False

for o, a in opts:
    if o == '-n':
        place_name = a
    elif o == '-c':
        line_color = a
    elif o == '-w':
        line_width = float(a)
    elif o == '-t':
        tilt = float(a)
    elif o == '-h':
        heading = float(a)
    elif o == '-r':
        range = float(a)
    elif o == '-s':
        tour_speed = float(a)
    elif o == '-l':
        latlng = a.split(',')
        lookAtLat = float(latlng[0])
        lookAtLng = float(latlng[1])
        forceLookAt = True
    elif o == '-f':
        if a == "YES":
            follow_path = True
        else:
            follow_path = False
    elif o == '-R':
        if a == "YES":
            reverse_path = True
        else:
            reverse_path = False

# read coordinates from standard-in
raw_coords = sys.stdin.read()

# Strip all whitespace from either end
raw_coords = raw_coords.strip(None)

string_coords = raw_coords.split(" ")

# --------------------------------------------------
# Convert the strings to floating point, and interpolate lines

max_points = 0

def dist(c1, c2):
    xdiff = c1[0] - c2[0]
    ydiff = c1[1] - c2[1]
    dist = math.sqrt(xdiff * xdiff + ydiff * ydiff)
    return dist

limit = 0

def segmentize(start, end, coords, scale):
    global limit
    global max_points
    limit += 1
    if max_points > 0:
        if limit > max_points: return
    if dist(start, end) < scale:
        coords.append(end)
    else:
        mid_x = (start[0] + end[0]) / 2.0
        mid_y = (start[1] + end[1]) / 2.0
        mid = (mid_x, mid_y)
        segmentize(start, mid, coords, scale)
        segmentize(mid, end, coords, scale)

coords = []
last_coord = None
i = 0

for s in string_coords:
    coord = s.split(",")
    c = (float(coord[0]), float(coord[1]))
    i += 1
    if i == 1:
        last_coord = c
        coords.append(c)
        continue
    segmentize(last_coord, c, coords, playback_smoothness)
    last_coord = c

maxdist = -1
below = 0
i = 0
culled_coords = []
for c in coords:
    i += 1
    if i == 1:
        last_coord = c
        continue
    d = dist(last_coord, c)
    if (d > maxdist): maxdist = d
    last_coord = c
    if d > playback_smoothness * 0.5: culled_coords.append(c)

coords = culled_coords

if reverse_path:
    coords.reverse()

# print "max is %f, len %d, below %d" % (maxdist, len(coords), below)

# sys.exit(0)


kml = """<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<Document>
        <name>%s</name>
        <open>1</open>
""" % place_name

screen_overlay = """
    <ScreenOverlay>
      <name>Logo</name>
            <visibility>1</visibility>
      <Icon>
        <href>/Users/markd/Movies/globalride/GlobalRide.png</href>
      </Icon>
            <overlayXY x="1" y="1" xunits="fraction" yunits="fraction"/>
            <screenXY x="1" y="1" xunits="fraction" yunits="fraction"/>
            <rotationXY x="0" y="0" xunits="fraction" yunits="fraction"/>
            <size x="0" y="0" xunits="fraction" yunits="fraction"/>
    </ScreenOverlay>
"""

# kml += screen_overlay

# --------------------------------------------------
# Styles


style = """
    <Style id="line_style">
        <LineStyle>
            <color>%s</color>
            <colorMode>normal</colorMode>
            <width>%f</width>
        </LineStyle>
    </Style>
""" % (line_color, line_width)

kml += style


# --------------------------------------------------
# make the tour groovies

start = coords[0]

if not follow_path:
    if forceLookAt:
        start = (lookAtLng, lookAtLat)
        
tour = """
<gx:Tour>
<name>Play me!</name>
<gx:Playlist>
<gx:FlyTo>
  <gx:duration>0</gx:duration>
  <LookAt>
                        <longitude>%s</longitude>
                        <latitude>%s</latitude>
                        <altitude>0</altitude>
                        <range>%f</range>
                        <tilt>%f</tilt>
                        <heading>%f</heading>
                        <altitudeMode>clampToGround</altitudeMode>
  </LookAt>
</gx:FlyTo>""" % (start[0], start[1], range, tilt, heading)


i = 0
c = None
last_coord = None
for c in coords:
    i += 1

    # skip the first one since we need a pair to build the linestring.
    if i == 1:
        last_coord = c
        continue

    update = """
    <gx:AnimatedUpdate>
      <gx:duration>%f</gx:duration>
      <Update>
        <targetHref></targetHref>
        <Change>
          <LineString targetId="line%d">
            <coordinates>%f,%f,0 %f,%f,0</coordinates>
          </LineString>
        </Change>
      </Update>
    </gx:AnimatedUpdate>
""" % (tour_speed, i - 1, last_coord[0], last_coord[1], c[0], c[1])

    tour += update

    if follow_path:
        c0 = c[0]
        c1 = c[1]
    else:
        c0 = coords[0][0]
        c1 = coords[0][1]
        if forceLookAt:
            c0 = lookAtLng
            c1 = lookAtLat

    flyto = """
  <gx:FlyTo>
    <gx:duration>%f</gx:duration>
    <gx:flyToMode>smooth</gx:flyToMode>
    <LookAt>
                        <longitude>%f</longitude>
                        <latitude>%f</latitude>
                        <altitude>0</altitude>
                        <range>%f</range>
                        <tilt>%f</tilt>
                        <heading>%f</heading>
                        <altitudeMode>clampToGround</altitudeMode>
    </LookAt>
  </gx:FlyTo>

""" % (tour_speed, c0, c1, range, tilt, heading)

    tour += flyto

    last_coord = c

tour += """
</gx:Playlist>
</gx:Tour>
"""


kml += tour


# --------------------------------------------------
# Container for the placemarks

folders = """
        <Folder>
                <open>0</open>
                <visibility>1</visibility>
"""

# --------------------------------------------------
# make the placemarks

i = 0
for c in coords:
    i += 1

    placemark = """
                <Placemark>
                        <name></name>
                        <styleUrl>#line_style</styleUrl>
                        <MultiGeometry>
                        <LineString id="line%d">
                           <tessellate>1</tessellate>
                           <coordinates>%f,%f,0</coordinates>
                        </LineString>
                        </MultiGeometry>
                </Placemark>
""" % (i, c[0], c[1])
    folders += placemark

kml += folders
kml += """
        </Folder>
"""


# --------------------------------------------------
# mop-up

kml += """
</Document>
</kml>
"""

print kml
